package org.maxgroundstation.groundstation.view;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.Iterator;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

import org.maxgroundstation.groundstation.GroundStation;
import org.maxgroundstation.groundstation.GroundStationEvent;
import org.maxgroundstation.groundstation.GroundStationListener;
import org.maxgroundstation.groundstation.comm.service.Service;
import org.maxgroundstation.groundstation.comm.service.ServiceEvent;
import org.maxgroundstation.groundstation.comm.service.ServiceListener;
import org.maxgroundstation.groundstation.comm.service.video.VideoService;

/**
 * A panel for displaying video feeds.
 * @author Scott Davis
 * 
 * Copyright (C) 2010  Scott Davis
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
@SuppressWarnings("serial")
public class VideoDisplay extends JPanel implements GroundStationListener, 
        ServiceListener {

    // Data members.
    private CameraPanel cp;
    
    /**
     * Constructor
     * @param gs the ground station.
     */
    public VideoDisplay(GroundStation gs, CameraPanel cp) {
        super();
        
        // Initialize data members.
        this.cp = cp;
        
        // Set background color to black.
        setBackground(Color.BLACK);
        
        // Register as ground station listener.
        gs.addGroundStationListener(this);
        
        // Create mouse listener.
        VideoImageMouseListener mouseListener = new VideoImageMouseListener(gs);
        addMouseListener(mouseListener);
        addMouseMotionListener(mouseListener);
    }

    @Override
    public void groundStationUpdate(GroundStationEvent event) {
        
        // If services initialized from robot, check for any video services.
        if (GroundStationEvent.SERVICES_INITIALIZED.equals(event.getType())) {
            GroundStation gs = (GroundStation) event.getSource();
            Iterator<Service> i = gs.getServiceComm().getServices().iterator();
            while (i.hasNext()) {
                Service service = i.next();
                
                // Subscribe to any services with "video" in their name.
                if (service.getName().toLowerCase().indexOf("video") >= 0) {
                    service.addServiceListener(this);
                    VideoDisplayUtil.addVideoServiceName(service.getName());
                }
            }
            
            // Set the current video service name to the first video service, if any.
            if (VideoDisplayUtil.getVideoServicesNames().size() > 0) {
                VideoDisplayUtil.setCurrentVideoServiceName(
                        VideoDisplayUtil.getVideoServicesNames().get(0));
            }
        }
        else if (GroundStationEvent.SERVICES_CLOSED.equals(event.getType())) {
            // If closing services, clear video service names.
            VideoDisplayUtil.clearVideoServiceNames();
            VideoDisplayUtil.setCurrentVideoServiceName(null);
        }
    }

    @Override
    public void serviceUpdate(ServiceEvent event) {
        
        if (VideoService.VIDEO_IMAGE_DATA_RECEIVED.equals(event.getType())) {
            Service service = (Service) event.getSource();
            byte[] imageData = (byte[]) event.getTarget();
            ImageIcon image = new ImageIcon(imageData);
            VideoDisplayUtil.setCurrentVideoImage(service.getName(), image);
            cp.repaint();
        }
    }
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        Graphics2D g2d = (Graphics2D) g;
        
        // If video image exists, display it.
        // Otherwise display "No Video Image" text.
        String selectedServiceName = VideoDisplayUtil.getCurrentVideoServiceName();
        ImageIcon videoImage = VideoDisplayUtil.getCurrentVideoImage(selectedServiceName);
        if (videoImage != null) {
            
            // Scale image by width and height of panel, but keep image proportion.
            int imageWidth = videoImage.getIconWidth();
            int imageHeight = videoImage.getIconHeight();
            double widthScale = (double) getWidth() / (double) imageWidth;
            double heightScale = (double) getHeight() / (double) imageHeight;
            if (widthScale < heightScale) heightScale = widthScale;
            else if (heightScale < widthScale) widthScale = heightScale;
            
            // Center image vertically and horizontally.
            int xPos = (int)(((getWidth() / widthScale) - videoImage.getIconWidth()) / 2.0);
            int yPos = (int)(((getHeight() / heightScale) - videoImage.getIconHeight()) / 2.0);
            
            // Set rendering hints.
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, 
                    RenderingHints.VALUE_RENDER_SPEED);
            
            g2d.scale(widthScale, heightScale);
            
            // Draw video image.
            videoImage.paintIcon(this, g2d, xPos, yPos);
        }
        else {
            g2d.setColor(Color.GREEN);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setFont(new Font(g2d.getFont().getFontName(), Font.BOLD, 20));
            String text = "No Video Image";
            int textWidth = g2d.getFontMetrics().stringWidth(text);
            int xPos = (getWidth() - textWidth) / 2;
            int textHeight = g2d.getFontMetrics().getHeight();
            int yPos = (getHeight() - textHeight) / 2;
            g2d.drawString(text, xPos, yPos);
        }
    }
}